package de.rs.espresso.tools.gui.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import de.rs.espresso.interfaces.ICover;
import de.rs.espresso.interfaces.ICube;
import de.rs.espresso.interfaces.IGlobalInformation;
import de.rs.espresso.tools.gui.model.Constraint.ConstraintDirection;
import de.rs.espresso.tools.gui.model.Constraint.ConstraintType;

public class KVModel {

	List<Field> fields;


	private ICover cover;

	private IGlobalInformation info;


	private String title;

	public KVModel(ICover cover, IGlobalInformation info, int output, String title) {
		this.cover = cover;
		this.info = info;

		this.title = title;
		
		fields = Field.createFields(info);

		int j = 0;

		for (ICube c : cover) {

			if (c.getOutput(output) == ICube.OUTPUT_PRESENT) {
				ArrayList<Field> fClone = new ArrayList<Field>();
				fClone.addAll(fields);

				for (int i = 0; i < info.getNumberOfInputs() ; i++) {
					byte input = c.getLiteral(i);

					if (input != ICube.DONT_CARE) {
						switch (i) {
						case 0:
							if(input==ICube.DIRECT)
								remove(fClone, ConstraintDirection.X,ConstraintType.BIGGER,1);
							else
								remove(fClone, ConstraintDirection.X,ConstraintType.SMALLER,2);								
							break;
						case 1:
							if(input==ICube.DIRECT)
								remove(fClone, ConstraintDirection.Y,ConstraintType.BIGGER,1);
							else
								remove(fClone, ConstraintDirection.Y,ConstraintType.SMALLER,2);		

							break;
						case 2:
							if(input==ICube.DIRECT) {
								remove(fClone, ConstraintDirection.X,ConstraintType.BIGGER,2);
								remove(fClone, ConstraintDirection.X,ConstraintType.SMALLER,1);
							}
							else {
								ArrayList<Field> keep = keep(fClone, ConstraintDirection.X,ConstraintType.BIGGER,2);
								keep.addAll(keep(fClone, ConstraintDirection.X,ConstraintType.SMALLER,1));
								fClone.retainAll(keep);
							}
							break;
						case 3:
							if(input==ICube.DIRECT) {
								remove(fClone, ConstraintDirection.Y,ConstraintType.BIGGER,2);
								remove(fClone, ConstraintDirection.Y,ConstraintType.SMALLER,1);
							}
							else {
								ArrayList<Field> keep = keep(fClone, ConstraintDirection.Y,ConstraintType.BIGGER,2);
								keep.addAll(keep(fClone, ConstraintDirection.Y,ConstraintType.SMALLER,1));
								fClone.retainAll(keep);
							}
							break;
						}
					}

				}

				for(Field f : fClone) {
					f.addCube(j);
				}
				
				j++;
			}
		}


	}

	private ArrayList<Field> keep(ArrayList<Field> fClone, ConstraintDirection dir,
			ConstraintType type, int i) {
		ArrayList<Field> toKeep = new ArrayList<Field>();
		for(Field f : fClone) {
			if(dir==ConstraintDirection.X) {
				if(type==ConstraintType.BIGGER) {
					if(f.y>i)
						toKeep.add(f);
				}
				else {
					if(f.y<i)
						toKeep.add(f);					
				}
			}
			else {
				if(type==ConstraintType.BIGGER) {
					if(f.x>i)
						toKeep.add(f);
				}
				else {
					if(f.x<i)
						toKeep.add(f);					
				}
			}
		}
		return toKeep;
		
	}

	private void remove(ArrayList<Field> fClone, ConstraintDirection dir,
			ConstraintType type, int i) {
		ArrayList<Field> toRemove = new ArrayList<Field>();
		for(Field f : fClone) {
			if(dir==ConstraintDirection.X) {
				if(type==ConstraintType.BIGGER) {
					if(f.y>i)
						toRemove.add(f);
				}
				else {
					if(f.y<i)
						toRemove.add(f);					
				}
			}
			else {
				if(type==ConstraintType.BIGGER) {
					if(f.x>i)
						toRemove.add(f);
				}
				else {
					if(f.x<i)
						toRemove.add(f);					
				}
			}
		}
		fClone.removeAll(toRemove);
	}

	public int getCubeCount() {
		return cover.size();
	}

	public List<Field> getFields() {
		return fields;
	}

	public boolean getContainedNeighbor(Field f, int c, int i) {
		int x = f.x, y = f.y;
		switch (i) {
		case 0:
			y = f.y - 1;
			break;
		case 1:
			x = f.x + 1;
			break;
		case 2:
			y = f.y + 1;
			break;
		case 3:
			x = f.x - 1;
			break;
		}

		if (y > 3)
			return false;
		if (x > 3)
			return false;

		if (y < 0)
			return false;
		if (x < 0)
			return false;

		for (Field f2 : fields) {
			if (f2.x == x && f2.y == y) {
				if (f2.contains(c))
					return true;
				else
					return false;
			}
		}

		return false;
	}

	public String getTitle() {
		return title;
	}

}
